
/*
数据库ObjectBox(ANDROID IOS LINUX MACOS WINDOWS),不支持web端
realm不支持分页, objectBox支持分页

https://pub.flutter-io.cn/packages/objectbox

dependencies:
  objectbox: ^2.4.0
  objectbox_flutter_libs: ^2.4.0
dev_dependencies:
  objectbox_generator: ^2.4.0

import 'package:objectbox/objectbox.dart';

适用复杂的后端离线数据存储方案:
实际使用过程中,ToMany/ToOne存在虚拟化和反序列化问题,
默认的gson不能解析,造成不便,需要添加对应的自定义TypeAdapter,
而且关系型数据库,内嵌套多张关系表,后期使用中,后端容易改变表结构字段等问题,前端也要升级数据库;
解决:
无论用ObjectBox(支持分页查询)/realm(不支持分页查询),都应该避免使用ToMany/ToOne/RealmList,
通过api返回的前端可用数据json结构, 整条保存json内容即可,需要查询的字段,再提取抽出对应字段,
组成没有关系的简单表结构使用(其中一个表字段是记录整个json内容),
这样可用很方便解决gson无法换BeanObjectBox的问题

作为api输出时,可用通用的类型输出,则不用建立对应的实体类:
// public class ResponseList{
//     public String msg;
//     public String code;
//     public long PageIndex;
//     public long PageCount;
//     public List<Map<String,Object>> items;
// }

注意:变更数据表结构(更改或删除字段)有可能导致安装运行失败,解决:删除app重新安装即可;


注意: android6.0(商米机) 提示objectbox-jni.so找不到报错,在初始化前需要手动加载so文件:
判断android机后调用:XFlutterPluginUtils.manualSystemLoadLibrary('objectbox-jni');
或者: XFFIUtils.loadLibrarySOFile('objectbox-jni'); //待测?

https://docs.objectbox.io/getting-started
  mac沙箱:
  在TARGETS->Runner->Signing & Capabilities-> + Capabilities -> App Groups 添加:FGDTDLOBXDJ.demo
  然后openStore(macosApplicationGroup: 'FGDTDLOBXDJ.demo')



注意:多个表一起执行时,最好开启事务,注意在事务内部能有await(即runInTransaction传参中的方法不能定义async)
dynamic res= store?.runInTransaction(TxMode.write,(){
  return XXX();
});


 */


/*
查询

orAny多个条件中任何一个成立则成立(包括orAny前面的条件): 名字=john或者age>18 都成立
name.equel('john').orAny([age>18,...]);


 */





/*
使用:

// 1.创建dart文件: models.dart, 使用@Entity()添加定义对应的实体类,
// 注意:每个实体类都必须有
//   @Id()
//   int id=0;
// 每个实体类都必须有构造函数

如:
// import 'package:objectbox/objectbox.dart';
// @Entity()
// class Person {
//   @Id()
//   int id = 0;
//   String? name;
//   @Property(type: PropertyType.date) // Store as int in milliseconds
//   DateTime? date;
//   @Transient() // Ignore this property, not stored in the database.
//   int? computedProperty;
//   Person({required this.name});
// }

// 2.使用命令生成ObjectBox文件:  flutter pub run build_runner build
// (这时生成2个文件: lib/objectbox.g.dart 和 lib/objectbox-model.json)
//
// 3.创建objectbox.dart文件, 注意:要创建任意一个 @Entity class并执行flutter pub run build_runner build

// import 'dart:async';
//
// import 'package:path/path.dart' as p;
// import 'package:path_provider/path_provider.dart';
//
// // 通过 `flutter pub run build_runner build`  生成的objectbox.g.dart
// import '../../../../objectbox.g.dart';
// import 'models.dart';
//
// //静态类,一次只启动一个数据库(可修改为实例,一次可启动多个数据库)
// class XObjectBoxUtils {
//   //在生成的objectbox.g.dart内
//   static Store? store;
//
//   static Box<BeanOfflineDBGood>? goodBox;
//   static Box<BeanOfflineDBGoodSpec>? goodSpecBox;
//   static Box<BeanOfflineDBOrder>? orderBox;
//   static Box<BeanOfflineDBPendingOrder>? pendingOrderBox;
//   static Box<TestDBItem>? testItemBox;
//
//   XObjectBoxUtils._create() {
//     // 初始化各个实体类对应box,等同: Box<BeanOfflineDBGood>(store!);
//     goodBox=store?.box<BeanOfflineDBGood>();
//     goodSpecBox=store?.box<BeanOfflineDBGoodSpec>();
//     orderBox=store?.box<BeanOfflineDBOrder>();
//     pendingOrderBox=store?.box<BeanOfflineDBPendingOrder>();
//     testItemBox=store?.box<TestDBItem>();
//   }
//
//   //1.初始化,可在app中初始化,或者在登录后调用接口获得对应的id使用不同的数据库
//   /*
//   //已在app中初始化: WidgetsFlutterBinding.ensureInitialized();
//   如:
//   await XObjectBoxUtils.create(dbname);
//    */
//   static Future<XObjectBoxUtils> create(String dbName) async {
//        XLogUtils.printLog('---XObjectBoxUtils,create');
//     if(store!=null){
//       store!.close();
//       store=null;
//     }
//     final docsDir = await getApplicationDocumentsDirectory();
//     //在生成的objectbox.g.dart内
//     store = await openStore(
//         directory: p.join(docsDir.path, dbName),
//         macosApplicationGroup: 'FGDTDLOBXDJ.demo',//用于macOS沙箱
//     );
//     return XObjectBoxUtils._create();
//   }
//
//
//   //test
//   static void saveTestDBItem(TestDBItem item){
//     testItemBox?.putAsync(item);
//   }
//   static void saveTestDBList(List<TestDBItem> items){
//     testItemBox?.putMany(items);
//   }
//
//   static void delTestDBItem(int id) {
//     testItemBox?.remove(id);
//   }
//   static void delAllTestDBItems() {
//     testItemBox?.removeAll();
//   }
//   static void delTestDBItemList(List<int> ids) {
//     testItemBox?.removeMany(ids);
//   }
//
//   static TestDBItem? getTestDBItemById(int id) {
//     return testItemBox?.get(id);
//   }
//   static List<TestDBItem>? getAllTestDBItems() {
//     return testItemBox?.getAll();
//   }
//
//   static List<TestDBItem>? getTestDBItems() {
//     final query =(testItemBox?.query(TestDBItem_.name.equals('Tom')).order(TestDBItem_.name))?.build();
//     final results = query?.find();
//     query?.close();
//     return results;
//   }
//
//
// }


操作:
https://docs.objectbox.io/getting-started

final userCount = userBox.count();

// Put a new object into the box
var person = Person(name: "Joe Green");
final id = box.put(person);

// Get the object back from the box
person = box.get(id)!;

// Update the object
person.name = "Joe Black";
box.put(person);

// Query for objects
final query = box.query(Person_.name.equal("Joe Black"))
        .order(Person_.name).build();
final people = query.find();
query.close();

// Remove the object from the box
box.remove(person.id);

 */


/*
查找:
static String getBeanOfflineDBGoodList(
      {
        required int pageIndex,
        required int pageSize,
        String? fCode,
        String? keyword
      }
      ) {


    ItemListResponse response =ItemListResponse();

    if (pageIndex<0||pageSize<=0){
      response.code="-1";
      return XJsonUtils.obj2Json(response);
    }

    //总页数
    int pageCount=0;
    //总商品数
    int totalCount=0;

    List<BeanOfflineDBGood> list=[];


    if (XStringUtils.isEmpty(keyword)){

      if (XStringUtils.isEmpty(fCode)){

        //计算分页,总商品数
        totalCount=goodBox!.count()??0;
        if (totalCount/pageSize==0){
          pageCount=1;
        }else{
          pageCount=(totalCount%pageSize==0)?(totalCount/pageSize).truncate():((totalCount/pageSize).truncate()+1);
        }
        //偏离数=当前页数(第一页从1开始)*每页数量
        int offset=(pageIndex-1)*pageSize;

        //全部分类
        Query<BeanOfflineDBGood> query =goodBox!.query().order(BeanOfflineDBGood_.id).build();
        query.limit=pageSize;
        query.offset=offset;
        list = query.find();
        query.close();

      }else{
        //按分类  同一张分类表支持多层,用contains,不用equal
        Query<BeanOfflineDBGood> query =goodBox!
            .query(BeanOfflineDBGood_.itemTypefCode.contains(fCode!))
            .order(BeanOfflineDBGood_.id).build();

        //计算分页,总商品数
        totalCount=query.count();
        if (totalCount/pageSize==0){
          pageCount=1;
        }else{
          pageCount=(totalCount%pageSize==0)?(totalCount/pageSize).truncate():((totalCount/pageSize).truncate()+1);
        }
        //偏离数=当前页数(第一页从1开始)*每页数量
        int offset=(pageIndex-1)*pageSize;

        query.limit=pageSize;
        query.offset=offset;
        list = query.find();
        query.close();

      }

    }else{
      //全部分类
      Query<BeanOfflineDBGood> query =goodBox!
          .query(
          BeanOfflineDBGood_.itemName.contains(keyword!)
              .or(BeanOfflineDBGood_.skuBarcode.contains(keyword!)
              .or(BeanOfflineDBGood_.itemCode.contains(keyword!)
              .or(BeanOfflineDBGood_.pinyin.contains(keyword!)
          ))))
          .order(BeanOfflineDBGood_.id).build();

      //计算分页,总商品数
      totalCount=query.count();
      if (totalCount/pageSize==0){
        pageCount=1;
      }else{
        pageCount=(totalCount%pageSize==0)?(totalCount/pageSize).truncate():((totalCount/pageSize).truncate()+1);
      }
      //偏离数=当前页数(第一页从1开始)*每页数量
      int offset=(pageIndex-1)*pageSize;

      query.limit=pageSize;
      query.offset=offset;
      list = query.find();
      query.close();
    }

    //
    List<Map<String,dynamic>> h5JsonList=[];

    for (BeanOfflineDBGood sItem in list){
      Map<String,dynamic> m=XJsonUtils.json2Object(sItem.json);
      //XLogUtils.printLog('-------m=${m.toString()}');
      h5JsonList.add(m);
    }

    response.code="200";
    response.msg='1213';
    response.PageIndex=pageIndex;
    response.PageCount=pageCount;
    response.totalCount=totalCount;
    response.items=h5JsonList;
    //response.items=[];

    //L.sdk("---分类商品搜索response="+XJsonUtils.obj2String(response));
    //XLogUtils.printLog('---分类商品搜索h5JsonList= ${h5JsonList.length}');

    return XJsonUtils.obj2Json(response);
  }


//查找规格,第一页从1开始
   static String getSpecItemList(int pageIndex, int pageSize, List<String> specIds){

    ItemListResponse response =ItemListResponse();

    try{

      if (pageIndex<0||pageSize<=0||specIds==null||specIds.length==0){
        response.code="-1";
        return XJsonUtils.obj2Json(response);
      }
      //
      List<BeanOfflineDBGoodSpec> list=[];
      Query<BeanOfflineDBGoodSpec>? query;
      Condition<BeanOfflineDBGoodSpec>? condition;

      for (int i=0;i<specIds.length;i++){
        if (i==0){
          condition=BeanOfflineDBGoodSpec_.specId.equals(specIds[0]);
        }else{
          //叠加
          condition!.or(BeanOfflineDBGoodSpec_.specId.equals(specIds[0]));
        }

        if (i==(specIds.length-1)){
          //最后叠加
          query=goodSpecBox!.query(condition).order(BeanOfflineDBGoodSpec_.id)
              .build();
        }

      }

      //总页数
      int pageCount=0;
      //计算总商品数
      int totalCount=query!.count();
      XLogUtils.printLog('---totalCount=$totalCount');
      if (totalCount/pageSize==0){
        pageCount=1;
      }else{
        pageCount=(totalCount%pageSize==0)?(totalCount/pageSize).truncate():((totalCount/pageSize).truncate()+1);
      }
      //偏离数=当前页数(第一页从1开始)*每页数量
      int offset=(pageIndex-1)*pageSize;

      query.limit=pageSize;
      query.offset=offset;
      list = query.find();
      query.close();

      XLogUtils.printLog('---规格list=${XJsonUtils.obj2Json(list)}');

      //
      List<Map<String,dynamic>> h5JsonList=[];

      for (BeanOfflineDBGoodSpec sItem in list){
        Map<String,dynamic> m=XJsonUtils.json2Object(sItem.json);
        //XLogUtils.printLog('-------m=${m.toString()}');
        h5JsonList.add(m);
      }

      response.code="200";
      response.PageIndex=pageIndex;
      response.PageCount=pageCount;
      response.totalCount=totalCount;
      response.items=h5JsonList;

    }catch (e){
      XLogUtils.printLog('---getSpecItemList报错: $e');
    }

    return XJsonUtils.obj2Json(response);

  }


 */


// abstract class XObjectBoxDBUtils{
// }
